package com.sky.service.impl;

import com.sky.dto.GoodsSalesDTO;
import com.sky.entity.Orders;
import com.sky.mapper.OrdersMapper;
import com.sky.mapper.UserMapper;
import com.sky.service.ReportService;
import com.sky.vo.*;
import io.swagger.models.auth.In;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.util.StringUtil;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * PROJECT_NAME: sky-take-out
 * NAME: ReportServiceImpl
 * USER: zhang
 * DATE: 2023/6/7
 * DESCRIPTION :B端-统计信息服务层接口实现类
 */
@Slf4j
@Service
public class ReportServiceImpl implements ReportService {
    @Resource
    private OrdersMapper ordersMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private WorkSpaceServiceImpl workSpaceServiceImpl;

    /**
     * 营业额统计
     *
     * @param begin 开始日期
     * @param end   结束日期
     * @return 全局通用返回信息Bean(日期列表 ， 营业额列表)
     */
    @Override
    public TurnoverReportVO selectTurnoverStatistics(LocalDate begin, LocalDate end) {
        //基于累加法将每天的LocalDate封装到List集合中
        ArrayList<LocalDate> dateArrayList = new ArrayList<>();
        //用于保存每天营业额的集合
        ArrayList<Double> turnoverArrayList = new ArrayList<>();
        //将第一天的LocalDate添加到集合中去
        dateArrayList.add(begin);
        while (!begin.equals(end)) {
            begin = begin.plusDays(1);
            dateArrayList.add(begin);
        }
        //遍历dateArrayList，获取每一天的LocalDate对象,将LocalDate转换为表示当天时间年月日时分秒对象
        dateArrayList.forEach(localDate -> {
            LocalDateTime startTime = LocalDateTime.of(localDate, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(localDate, LocalTime.MAX);
            //基于订单持久层查询当天订单营业额
            Double dayAmount = ordersMapper.selectAmountByOrderStatusAndOrderTime(Orders.COMPLETED, startTime, endTime);
            //如果当天的营业额为NULL,避免空指针将当天营业额赋值为0.0
            if (Objects.isNull(dayAmount)) {
                dayAmount = 0.0;
            }
            turnoverArrayList.add(dayAmount);
        });
        //基于StringUtils工具类join方法传递一个集合、分隔符，自动将集合中的内容通过元素，分隔符拼接成字符串
        String resultDateTime = StringUtils.join(dateArrayList, ",");
        String resultTurnover = StringUtils.join(turnoverArrayList, ",");
        return TurnoverReportVO.builder().dateList(resultDateTime).turnoverList(resultTurnover).build();
    }

    /**
     * 指定时间区间用户统计
     *
     * @param begin 开始日期
     * @param end   结束日期
     * @return 全局通用返回信息Bean(日期列表 ， 用户总量 ， 新增用户)
     */
    @Override
    public UserReportVO selectUserStatistics(LocalDate begin, LocalDate end) {
        //创建一个List集合用于保存每天的LocalDate
        ArrayList<LocalDate> dateArrayList = new ArrayList<>();
        //创建一个List集合用于保存每天新增用户数量
        ArrayList<Integer> newUserArrayList = new ArrayList<>();
        //创建一个List集合用于每天保存用户总量
        ArrayList<Integer> totalUserArrayList = new ArrayList<>();
        //基于累加法将每天的LocalDate保存到dateArrayList集合中
        dateArrayList.add(begin);
        while (!begin.equals(end)) {
            begin = begin.plusDays(1);
            dateArrayList.add(begin);
        }
        //遍历dateArrayList，获取每一天的LocalDate对象,将LocalDate转换为表示当天时间年月日时分秒对象
        dateArrayList.forEach(localDate -> {
            LocalDateTime startTime = LocalDateTime.of(localDate, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(localDate, LocalTime.MAX);
            //基于用户持久层查询当天新增用户
            Integer newUserCount = userMapper.selectUserCountByTime(startTime, endTime);
            //如果查询出来地新增用户为NULL说明没有新增直接复制为0
            if (Objects.isNull(newUserCount)) {
                newUserCount = 0;
            }
            //将查询出来的新增用户放到新增用户集合中
            newUserArrayList.add(newUserCount);
            //基于用户持久层查询用户总量
            Integer totalUserCount = userMapper.selectUserCountByTime(null, endTime);
            if (Objects.isNull(totalUserCount)) {
                totalUserCount = 0;
            }
            //将查询出来的用户总量放到用户总量集合中
            totalUserArrayList.add(totalUserCount);
        });
        //基于StringUtils工具类join方法传递一个集合、分隔符，自动将集合中的内容通过元素，分隔符拼接成字符串
        String resultDateStr = StringUtils.join(dateArrayList, ",");
        String resultNewUser = StringUtils.join(newUserArrayList, ",");
        String resultTotalUser = StringUtils.join(totalUserArrayList, ",");
        return UserReportVO.builder().dateList(resultDateStr).newUserList(resultNewUser).totalUserList(resultTotalUser).build();
    }

    /**
     * 指定时间区间订单统计
     *
     * @param begin 开始日期
     * @param end   结束日期
     * @return 全局通用返回信息Bean(OrderReportVO)
     */
    @Override
    public OrderReportVO selectOrdersStatistics(LocalDate begin, LocalDate end) {
        //创建List集合用于保存每天的LocalDate对象
        ArrayList<LocalDate> dateArrayList = new ArrayList<>();
        //创建一个List集合用于保存每天有效订单数量
        ArrayList<Integer> validArrayList = new ArrayList<>();
        //创建一个List集合用于保存每日订单数量
        ArrayList<Integer> dayOrderList = new ArrayList<>();
        //基于累加法将每天的日期添加到dateArrayList集合中
        dateArrayList.add(begin);
        while (!begin.equals(end)) {
            begin = begin.plusDays(1);
            dateArrayList.add(begin);
        }
        //遍历dateArrayList，获取每一天的LocalDate对象,将LocalDate转换为表示当天时间年月日时分秒对象
        dateArrayList.forEach(localDate -> {
            LocalDateTime startTime = LocalDateTime.of(localDate, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(localDate, LocalTime.MAX);
            //基于订单持久层查询每天有效的订单数量
            Integer validOrderCount = ordersMapper.selectValidOrderCount(Orders.COMPLETED, startTime, endTime);
            if (Objects.isNull(validOrderCount)) {
                validOrderCount = 0;
            }
            //将查询出来的有效订单数量放到validArrayList中去
            validArrayList.add(validOrderCount);
            //基于订单持久层查询每日订单数量
            Integer dayOrderCount = ordersMapper.selectValidOrderCount(null, startTime, endTime);
            if (Objects.isNull(dayOrderCount)) {
                dayOrderCount = 0;
            }
            dayOrderList.add(dayOrderCount);

        });
        //基于StringUtils工具类join方法传递一个集合、分隔符，自动将集合中的内容通过元素，分隔符拼接成字符串
        String resultDateStr = StringUtils.join(dateArrayList, ",");
        String resultValidStr = StringUtils.join(validArrayList, ",");
        String resultDayOrderTotalStr = StringUtils.join(dayOrderList, ",");
        //计算总订单数
        Integer totalOrderCount = 0;
        for (Integer integer : dayOrderList) {
            totalOrderCount += integer;
        }
        //计算有效订单数
        Integer validOrderCount = 0;
        for (Integer integer : validArrayList) {
            validOrderCount += integer;
        }
        //指定时间段订单完成率(判断总订单数是否为0，如果为0，直接赋值完成率为0.0。如果不为0，再进行计算)
        Double orderCompletionRate = 0.0;
        if (totalOrderCount != 0) {
            orderCompletionRate = (double) validOrderCount / totalOrderCount;
        }
        return OrderReportVO.builder()
                .dateList(resultDateStr)
                .orderCountList(resultDayOrderTotalStr)
                .validOrderCountList(resultValidStr)
                .totalOrderCount(totalOrderCount)
                .validOrderCount(validOrderCount)
                .orderCompletionRate(orderCompletionRate).build();
    }

    /**
     * 查询销量排名top10接口
     *
     * @param begin 开始日期
     * @param end   结束日期
     * @return 全局通用返回信息Bean(SalesTop10ReportVO)
     */
    @Override
    public SalesTop10ReportVO selectTop10(LocalDate begin, LocalDate end) {
        //将LocalDate转换为表示当天时间年月日时分秒对象
        LocalDateTime startTime = LocalDateTime.of(begin, LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.of(end, LocalTime.MAX);
        //将每一行数据封装为GoodSalesDTO集合,调用持久层进行查询
        List<GoodsSalesDTO> goodsSalesDTOList = ordersMapper.selectTop10(startTime, endTime);

        List<String> nameList = goodsSalesDTOList.stream().map(goodsSalesDTO -> goodsSalesDTO.getName()).collect(Collectors.toList());
        List<Integer> numberList = goodsSalesDTOList.stream().map(goodsSalesDTO -> goodsSalesDTO.getNumber()).collect(Collectors.toList());
        String nameStr = StringUtils.join(nameList, ",");
        String numberStr = StringUtils.join(numberList, ",");
        return SalesTop10ReportVO.builder().nameList(nameStr).numberList(numberStr).build();
    }

    /**
     * 导出近30天的报表数据
     *
     * @param httpServletResponse 在服务端直接基于HttpServletResponse对象向客户端进行响应
     */
    @SneakyThrows
    @Override
    public void export30DBusinessDate(HttpServletResponse httpServletResponse) {
        //(1)获取要读取的运营数据报表.xlsx文件
        //is:绑定了当前项目resource文件夹中运营数据报表.xlsx的字节输入流
        InputStream is = this.getClass().getClassLoader().getResourceAsStream("template\\运营数据报表.xlsx");
        //FileInputStream fis = new FileInputStream(new File("D:\\java-project\\sky-take-out\\sky-service\\src\\main\\resources\\template\\运营数据报表.xlsx"));

        //(2)将is绑定的文件内容读取到一个XSSFWorkBook
        XSSFWorkbook xssfWorkbook = new XSSFWorkbook(is);
        //(3)获取第一个工作表
        XSSFSheet sheet1 = xssfWorkbook.getSheetAt(0);

        //(4)完成部分一内容填充
        LocalDate startDate = LocalDate.now().minusDays(30);
        LocalDate endDate = LocalDate.now().minusDays(1);
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
        String startDateStr = dateTimeFormatter.format(startDate);
        String endDateStr = dateTimeFormatter.format(endDate);
        sheet1.getRow(1).getCell(1).setCellValue(startDateStr + "至" + endDateStr);

        //(5)完成部分二概览数据填充
        LocalDateTime startDateTime = LocalDateTime.of(startDate, LocalTime.MIN);
        LocalDateTime endDateTime = LocalDateTime.of(endDate, LocalTime.MAX);
        BusinessDataVO businessDataVO = workSpaceServiceImpl.selectBusinessData(startDateTime, endDateTime);
        sheet1.getRow(3).getCell(2).setCellValue(businessDataVO.getTurnover());
        sheet1.getRow(3).getCell(4).setCellValue(businessDataVO.getOrderCompletionRate());
        sheet1.getRow(3).getCell(6).setCellValue(businessDataVO.getNewUsers());
        sheet1.getRow(4).getCell(2).setCellValue(businessDataVO.getValidOrderCount());
        sheet1.getRow(4).getCell(4).setCellValue(businessDataVO.getUnitPrice());

        //(6)完成部分三明细数据填充
        for (int rowIndex = 7; rowIndex < 37; rowIndex++, startDate = startDate.plusDays(1)) {
            XSSFRow row = sheet1.getRow(rowIndex);
            BusinessDataVO businessData =
                    workSpaceServiceImpl.selectBusinessData(LocalDateTime.of(startDate, LocalTime.MIN),
                            LocalDateTime.of(startDate, LocalTime.MAX));
            row.getCell(1).setCellValue(dateTimeFormatter.format(startDate));
//            String turnover = Objects.isNull(businessData.getTurnover()) ? "¥0.0" : "¥"+businessData.getTurnover().toString();
//            row.getCell(2).setCellValue(turnover);
            row.getCell(2).setCellValue(businessData.getTurnover());
            row.getCell(3).setCellValue(businessData.getValidOrderCount());
            row.getCell(4).setCellValue(businessData.getOrderCompletionRate());
            row.getCell(5).setCellValue(businessData.getUnitPrice());
            row.getCell(6).setCellValue(businessData.getNewUsers());
        }
        //(7)获取响应对象输出流，将XSSFWorkbook响应给客户端
        ServletOutputStream os = httpServletResponse.getOutputStream();
        xssfWorkbook.write(os);

        //释放资源
        os.close();
        xssfWorkbook.close();
        is.close();
    }
}
